#include <iostream>
#include <fstream>
#include <algorithm>
#include <sstream>
#include "MovieDatabase.h"

using namespace std;

MovieDatabase::MovieDatabase(void)
{
   //vector<IMDBFileHeader> movieDBFiles;
   //multimap<Movie, Actor> movies;
   //multimap<Person, Movie> actors;

}


MovieDatabase::~MovieDatabase(void)
{
}

vector<Movie> MovieDatabase::GetBodyOfWork(const Person& actor)
{
   vector<Movie> results;
   ACTORS_ITERATOR item = actors.find(actor);
   if (item == actors.end())
      return results;
   results.resize(item->second.size());
   copy(item->second.begin(), item->second.end(), results.begin());
   return results;
}

vector<Person> MovieDatabase::SearchActors(const string& name, bool matchFullName)
{
   vector<Person> results;

   if(matchFullName)
   {
      size_t nameIndex = name.find(' ');
      if (nameIndex != string::npos)
      {
         string firstName = name.substr(0, nameIndex);
         string lastName = name.substr(nameIndex+1);
         Person person(firstName, lastName);
         ACTORS_ITERATOR item = actors.find(person);
         if (item != actors.end())
            results.push_back(item->first);
      }
   }
   else
   {
      //find_if(actors.begin(), actors.end(), 
   }
   return results;
}

vector<Actor> MovieDatabase::Cast(const Movie& movie)
{
   vector<Actor> results;
   MOVIES_ITERATOR item = movies.find(movie);
   if (item == movies.end())
      return results;
   results.resize(item->second.size());
   copy(item->second.begin(), item->second.end(), results.begin());
   return results;
}

void MovieDatabase::ImportIMDBFile(const string& filename) throw (invalid_argument)
{
   ifstream databaseFile(filename);
   if (!databaseFile.is_open())
      throw invalid_argument(filename + " failed to open");
   IMDBFileHeader imdbFile(databaseFile);
   for(size_t ix = 0; ix < movieDBFiles.size(); ix++)
   {
      if (imdbFile.crc == movieDBFiles[ix].crc)
      {
         cout << "Database file already imported" << endl;
         return;
      }
   }
   movieDBFiles.push_back(imdbFile);
   cout << "Importing data file " << imdbFile.originalFileName << endl;
   cout << "Created on: " << imdbFile.dateCreated << endl;
   cout << imdbFile.copyright << endl;
   int recordsParsed = 0;
   while(databaseFile)
   {
      if (!ParseRecord(databaseFile))
         break;
      recordsParsed++;
      if (recordsParsed % 100 == 0)
         cout << "\rProcessing Records - " <<  recordsParsed;
   }
   cout << "\rImport completed sucessfully. Added " << recordsParsed << " actors/actresses." << endl;
   databaseFile.close();
}

inline static bool isNotTabChar(int val)
{
   return val != '\t';
}

bool MovieDatabase::ParseRecord(istream& source)
{
   string actorString, movieString, characterName;

   getline(source, actorString, '\t');
   if (actorString.empty())
      return false;
   size_t nameSeperatorLocation = actorString.find(',');
   Person person(actorString.substr(nameSeperatorLocation + 2), actorString.substr(0, nameSeperatorLocation));
   Movie newMovie;
   Actor tempActor;
   newMovie.YearProduced = 0;
   while(source)
   {
      getline(source, movieString);
      if (movieString.empty())
         break;
      movieString.erase(movieString.begin(),find_if(movieString.begin(), movieString.end(), isNotTabChar));
      size_t titleEndIndex, titleStartIndex = 0;
      if (movieString[0] == '"')
      {
         titleStartIndex = 1;
         titleEndIndex = movieString.find('"', 1);
      }
      else
      {
         titleStartIndex = 0;
         titleEndIndex = movieString.find('(') - 1;
      }
      newMovie.Title = movieString.substr(titleStartIndex, titleEndIndex);
      /*
      size_t yearIndex = movieString.find('(', titleEndIndex)+1;
      istringstream movieStream(movieString);
      movieStream.ignore(yearIndex + 1);
      movieStream >> newMovie.YearProduced;
      size_t characterIndex = movieString.find('[', yearIndex+1);
      if (characterIndex != string::npos)
      {
         characterIndex++;
         characterName = movieString.substr(characterIndex, movieString.find(']', characterIndex)-characterIndex);
      }
      else
         characterName  = "";
      */
      newMovie.Type = Unknown;
      actors[person].push_back(newMovie);
      tempActor.SetPerson(person);
      tempActor.SetCharacterName(characterName);
      //tempActor.SetCreditsBillingPosition(billingPosition);
      movies[newMovie].push_back(tempActor);
   }
   return true;
}

int MovieDatabase::MovieCount() const
{
   return movies.size();
}

int MovieDatabase::ActorCount() const
{
   return actors.size();
}

bool MovieDatabase::IsPotentialMatch(const string& name, const Person& person) const
{
   return person.FullName().find(name, 0) != string::npos;
}

bool MovieDatabase::IsPotentialMatch(const string& name, const Movie& movie) const
{
   return movie.Title.find(name, 0) != string::npos;
}

